package com.jg.visitor.config.autoconfiguration.caffeinecache.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 缓存操作服务,会被自动加载进ioc
 */
@Slf4j
public class CacheService
{
    @Resource
    private CacheManager caffeineCacheManager;

    /**
     * 获取缓存
     * @param cacheName 缓存名称
     * @param key key
     * @param clazz class
     * @param <T> 泛型
     * @return 缓存对象
     */
    public <T> T getCache(String cacheName, String key, Class<T> clazz){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        return cache.get(key, clazz);
    }

    /**
     * 添加缓存
     * @param cacheName 缓存名称
     * @param key key
     * @param value value
     */
    public void put(String cacheName, String key, Object value){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        cache.put(key, value);
    }

    /**
     * 判断key是否存在
     * @param cacheName 缓存名称
     * @param key key
     * @return 存在返回true，不存在返回false
     */
    public boolean isKeyExist(String cacheName, String key){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        Cache.ValueWrapper value = cache.get(key);

        return value != null;
    }

    /**
     * 清除缓存
     * @param cacheName 缓存名称
     * @param key  key
     */
    public void evict(String cacheName, String key){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        cache.evict(key);
    }

    /**
     * 清空所有缓存
     * @param cacheName 缓存名称
     */
    public void clear(String cacheName){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        cache.clear();
    }

    /**
     * 获取所有缓存
     * @param cacheName 缓存名称
     * @return 所有缓存
     */
    public Map<String, Object> getAllCache(String cacheName){
        Cache cache = caffeineCacheManager.getCache(cacheName);

        if(cache == null){
            throw new RuntimeException("can not find the cache with name" + cacheName);
        }

        return cacheToMap(cache);
    }

    @SuppressWarnings("all")
    private static Map<String, Object> cacheToMap(Cache cache) {
        Object obj = cache.getNativeCache();
        Map<String, Object> map = new HashMap<>();
        Field[] fields = obj.getClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            log.error("ObjToMap exp", e);
            return null;
        }
        // 获取Cache.map中的cache
        return (Map<String, Object>) map.get("cache");
    }
}
